package com.example.tetris.logics.controller;

import com.example.tetris.App;
import com.example.tetris.gui.GamePageController;
import com.example.tetris.logics.components.*;
import com.example.tetris.logics.event.Event;
import javafx.animation.Timeline;

import java.io.Serializable;
import java.util.List;

public class GameManager implements Serializable ,InputEventHandler{


    Board board;
    Brick currentBrick;
    Brick nextBrick;
    /**
     * 用来记录需要绘制的cells
     */
    private ViewData viewData;
    public static int BOARD_WIDTH = 10;
    public static int BOARD_HEIGHT = 20;
    transient GamePageController gamePageController;

    boolean generateNewBrick = true;
    private ScoreInfo scoreInfo;



    public GameManager(GamePageController gamePageController){
        this.gamePageController = gamePageController;
        board = new Board(BOARD_WIDTH,BOARD_HEIGHT);
        nextBrick = Brick.generateRandomBrick(board);
        scoreInfo = new ScoreInfo();

    }
    @Override
    public void onDownEvent(Event eventSource){
        if(eventSource == Event.THREAD && generateNewBrick){//如果已经没有正在下落的砖块，产生新砖块
            generateNewBrick = false;
            currentBrick = nextBrick;
            nextBrick = Brick.generateRandomBrick(board);
            if(!currentBrick.canFall()){//已经容不下一个新砖块了
                //TODO
                gamePageController.gameOver();
                return;
            }
        }

        boolean canMove = currentBrick.moveDown();
        if(eventSource == Event.THREAD && !canMove){
            generateNewBrick = true;
            currentBrick.setFixedOnBoard();
            updateViewData();
            gamePageController.paintBoard();
            int fullRowNum = handleFullRows();
            if(fullRowNum != 0){
                int scoreToAdd = ScoreInfo.scoreOnRowCleared(fullRowNum);
                gamePageController.addScoreAnimation(scoreToAdd);
            }

            //TODO
        }else if(canMove){
            updateViewData();
            gamePageController.paintBoard();
        } else if (eventSource == Event.USER && !canMove) {//不能移动砖块时还试图move down是不允许的
            //do nothing
        }

    }

    private int handleFullRows() {
        List<Integer> fullRows = board.handleFullRows();
        int fullRowsNum = fullRows.size();
        scoreInfo.bonusOnDrop(fullRowsNum);
        if(fullRows.isEmpty()){
            updateViewData();
            gamePageController.paintBoard();
            return 0;
        }
        int[] rowIndexes = new int[fullRows.size()];
        for (int i = 0; i < rowIndexes.length; i++) {
            rowIndexes[i] = fullRows.get(i);
        }
        Timeline delRowAnimationTimeLine = gamePageController.delRowAnimation(rowIndexes);
        //动画结束再更新地图
        delRowAnimationTimeLine.setOnFinished(e->{
            updateViewData();
            gamePageController.paintBoard();
        });
        return fullRowsNum;
    }

    @Override
    public void onFallEvent() {
        if(currentBrick.isFixed()){
            return;//一个brick只能对于下落做出一次反应。
        }
        boolean canMove = true;
        while (canMove){
            canMove = currentBrick.moveDown();
        }
        generateNewBrick = true;
        currentBrick.setFixedOnBoard();
        updateViewData();
        gamePageController.paintBoard();
        int fullRowNum = handleFullRows();
        if(fullRowNum != 0){
            int scoreToAdd = ScoreInfo.scoreOnRowCleared(fullRowNum);
            gamePageController.addScoreAnimation(scoreToAdd);
        }
    }

    @Override
    public void onLeftEvent() {
        if(currentBrick.isFixed()){
            return;//一个brick固定后不应再次响应
        }
        boolean canMove = currentBrick.moveLeft();
        if(!canMove){
            //TODO:左移失败后的操作
        }
        updateViewData();
        gamePageController.paintBoard();
    }

    @Override
    public void onRigntEvent() {
        if(currentBrick.isFixed()){
            return;//一个brick固定后不应再次响应
        }
        boolean canMove = currentBrick.moveRight();
        if(!canMove){
            //TODO:右移失败后的操作
        }
        updateViewData();
        gamePageController.paintBoard();
    }

    @Override
    public void onRotateEvent() {
        if(currentBrick.isFixed()){
            return;//一个brick固定后不应再次响应
        }
        boolean canRotate = currentBrick.rotate();
        updateViewData();
        gamePageController.paintBoard();
    }



    private void updateViewData(){
        CellList brickCells = currentBrick.getBrickCellsOccupied();
        CellList fixedBoardCells = board.getCellsFixed();
        CellList cellListToPaint = new CellList();

        //如果已经固定在board上，那么这时brick的坐标已经无意义了
        if (!currentBrick.isFixed()) {
            for(Cell cell : brickCells.getCells()){
                cellListToPaint.addCell(cell);
            }
        }
        for(Cell cell : fixedBoardCells.getCells()){
            cellListToPaint.addCell(cell);
        }
        this.viewData = new ViewData(cellListToPaint,nextBrick.getShape(), scoreInfo);
    }

    /**
     *
     * @return 得到需要绘制的cells
     */
    public ViewData getViewData(){
        return viewData;
    }

    public void setGamePageController(GamePageController gamePageController){
        this.gamePageController = gamePageController;
    }


}

